1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.util.concurrent;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static java.util.concurrent.TimeUnit.MILLISECONDS;
21 import static java.util.concurrent.TimeUnit.NANOSECONDS;
22 import static junit.framework.Assert.fail;
23
24 import com.google.common.testing.TearDown;
25 import com.google.common.testing.TearDownAccepter;
26
27 import java.util.concurrent.TimeUnit;
28 import java.util.logging.Logger;
29
30
31
32
33
34
35
36 final class InterruptionUtil {
37 private static final Logger logger =
38 Logger.getLogger(InterruptionUtil.class.getName());
39
40
41
42
43 private static final class Interruptenator implements Runnable {
44 private final long everyMillis;
45 private final Thread interruptee;
46 private volatile boolean shouldStop = false;
47
48 Interruptenator(Thread interruptee, long everyMillis) {
49 this.everyMillis = everyMillis;
50 this.interruptee = interruptee;
51 }
52
53 @Override
54 public void run() {
55 while (true) {
56 try {
57 Thread.sleep(everyMillis);
58 } catch (InterruptedException e) {
59
60 }
61 if (shouldStop) {
62 break;
63 }
64 interruptee.interrupt();
65 }
66 }
67
68 void stopInterrupting() {
69 shouldStop = true;
70 }
71 }
72
73
74
75
76 static void requestInterruptIn(final long time, final TimeUnit unit) {
77 checkNotNull(unit);
78 final Thread interruptee = Thread.currentThread();
79 new Thread(new Runnable() {
80 @Override
81 public void run() {
82 try {
83 unit.sleep(time);
84 } catch (InterruptedException wontHappen) {
85 throw new AssertionError(wontHappen);
86 }
87 interruptee.interrupt();
88 }
89 }).start();
90 }
91
92 static void repeatedlyInterruptTestThread(
93 long interruptPeriodMillis, TearDownAccepter tearDownAccepter) {
94 final Interruptenator interruptingTask =
95 new Interruptenator(Thread.currentThread(), interruptPeriodMillis);
96 final Thread interruptingThread = new Thread(interruptingTask);
97 interruptingThread.start();
98 tearDownAccepter.addTearDown(new TearDown() {
99 @Override public void tearDown() throws Exception {
100 interruptingTask.stopInterrupting();
101 interruptingThread.interrupt();
102 joinUninterruptibly(interruptingThread, 2500, MILLISECONDS);
103 Thread.interrupted();
104 if (interruptingThread.isAlive()) {
105
106 logger.severe(
107 "InterruptenatorTask did not exit; future tests may be affected");
108
109
110
111
112 fail();
113 }
114 }
115 });
116 }
117
118
119 private static void joinUninterruptibly(
120 Thread thread, long timeout, TimeUnit unit) {
121 boolean interrupted = false;
122 try {
123 long remainingNanos = unit.toNanos(timeout);
124 long end = System.nanoTime() + remainingNanos;
125
126 while (true) {
127 try {
128
129 NANOSECONDS.timedJoin(thread, remainingNanos);
130 return;
131 } catch (InterruptedException e) {
132 interrupted = true;
133 remainingNanos = end - System.nanoTime();
134 }
135 }
136 } finally {
137 if (interrupted) {
138 Thread.currentThread().interrupt();
139 }
140 }
141 }
142 }